"""
工具模块
提供URL验证、文件处理等工具函数
"""
import re
import os
import validators
from urllib.parse import urlparse, unquote
from typing import Optional, Tuple
import mimetypes


class URLValidator:
    """URL验证器类"""
    
    # 支持的视频文件扩展名
    VIDEO_EXTENSIONS = {
        '.mp4', '.avi', '.mov', '.wmv', '.flv', '.webm', 
        '.mkv', '.m4v', '.3gp', '.ogv', '.ts', '.m3u8'
    }
    
    # 常见视频网站域名模式
    VIDEO_SITES = {
        'youtube.com', 'youtu.be', 'vimeo.com', 'dailymotion.com',
        'twitch.tv', 'bilibili.com', 'iqiyi.com', 'youku.com',
        'tencent.com', 'qq.com'
    }
    
    @staticmethod
    def is_valid_url(url: str) -> bool:
        """验证URL格式是否有效"""
        try:
            return validators.url(url) is True
        except Exception:
            return False
    
    @staticmethod
    def is_video_url(url: str) -> bool:
        """判断URL是否可能是视频链接"""
        if not URLValidator.is_valid_url(url):
            return False
        
        parsed = urlparse(url.lower())
        
        # 检查文件扩展名
        path = unquote(parsed.path)
        _, ext = os.path.splitext(path)
        if ext in URLValidator.VIDEO_EXTENSIONS:
            return True
        
        # 检查域名
        domain = parsed.netloc.lower()
        for site in URLValidator.VIDEO_SITES:
            if site in domain:
                return True
        
        return False
    
    @staticmethod
    def extract_filename_from_url(url: str) -> Optional[str]:
        """从URL中提取文件名"""
        try:
            parsed = urlparse(url)
            path = unquote(parsed.path)
            filename = os.path.basename(path)
            
            if filename and '.' in filename:
                return filename
            
            # 如果没有文件名，生成一个
            if parsed.netloc:
                return f"video_from_{parsed.netloc.replace('.', '_')}.mp4"
            
            return "downloaded_video.mp4"
        except Exception:
            return "downloaded_video.mp4"
    
    @staticmethod
    def get_content_type_from_url(url: str) -> Optional[str]:
        """根据URL猜测内容类型"""
        try:
            parsed = urlparse(url)
            path = unquote(parsed.path)
            content_type, _ = mimetypes.guess_type(path)
            return content_type
        except Exception:
            return None


class FileHelper:
    """文件处理助手类"""
    
    @staticmethod
    def sanitize_filename(filename: str) -> str:
        """清理文件名中的非法字符"""
        # 移除或替换非法字符
        illegal_chars = r'[<>:"/\\|?*]'
        sanitized = re.sub(illegal_chars, '_', filename)
        
        # 移除连续的下划线
        sanitized = re.sub(r'_+', '_', sanitized)
        
        # 移除首尾的点和空格
        sanitized = sanitized.strip('. ')
        
        # 确保文件名不为空
        if not sanitized:
            sanitized = "untitled"
        
        # 限制文件名长度
        if len(sanitized) > 200:
            name, ext = os.path.splitext(sanitized)
            max_name_len = 200 - len(ext)
            sanitized = name[:max_name_len] + ext
        
        return sanitized
    
    @staticmethod
    def ensure_extension(filename: str, default_ext: str = ".mp4") -> str:
        """确保文件有扩展名"""
        if not os.path.splitext(filename)[1]:
            return filename + default_ext
        return filename
    
    @staticmethod
    def get_safe_path(directory: str, filename: str) -> str:
        """获取安全的文件路径，避免重名"""
        filename = FileHelper.sanitize_filename(filename)
        full_path = os.path.join(directory, filename)
        
        if not os.path.exists(full_path):
            return full_path
        
        # 如果文件已存在，添加数字后缀
        name, ext = os.path.splitext(filename)
        counter = 1
        
        while os.path.exists(full_path):
            new_filename = f"{name}_{counter}{ext}"
            full_path = os.path.join(directory, new_filename)
            counter += 1
        
        return full_path
    
    @staticmethod
    def ensure_directory_exists(path: str) -> bool:
        """确保目录存在"""
        try:
            os.makedirs(path, exist_ok=True)
            return True
        except Exception:
            return False
    
    @staticmethod
    def format_file_size(size_bytes: int) -> str:
        """格式化文件大小显示"""
        if size_bytes == 0:
            return "0 B"
        
        for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
            if size_bytes < 1024.0:
                return f"{size_bytes:.1f} {unit}"
            size_bytes /= 1024.0
        
        return f"{size_bytes:.1f} PB"
    
    @staticmethod
    def format_speed(bytes_per_second: float) -> str:
        """格式化下载速度显示"""
        return f"{FileHelper.format_file_size(int(bytes_per_second))}/s"


class NetworkHelper:
    """网络助手类"""
    
    @staticmethod
    def get_headers() -> dict:
        """获取默认的HTTP头"""
        return {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
            'Accept': '*/*',
            'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
            'Accept-Encoding': 'gzip, deflate',
            'Connection': 'keep-alive',
        }
    
    @staticmethod
    def is_valid_response(response) -> bool:
        """检查HTTP响应是否有效"""
        try:
            response.raise_for_status()
            content_type = response.headers.get('content-type', '').lower()
            
            # 检查是否是视频内容
            if any(vtype in content_type for vtype in ['video/', 'application/octet-stream']):
                return True
            
            # 检查内容长度
            content_length = response.headers.get('content-length')
            if content_length and int(content_length) > 1024:  # 至少1KB
                return True
            
            return False
        except Exception:
            return False